package cn.itsource.system.service.impl;

import cn.hutool.crypto.SecureUtil;
import cn.itsource.base.service.impl.BaseServiceImpl;
import cn.itsource.base.util.*;
import cn.itsource.global.exception.BusinessException;
import cn.itsource.system.domain.*;
import cn.itsource.system.domain.dto.BindDto;
import cn.itsource.system.domain.dto.LoginDto;
import cn.itsource.system.domain.dto.PhoneUserFormRegisterDto;
import cn.itsource.system.mapper.LogininfoMapper;
import cn.itsource.system.mapper.UserMapper;
import cn.itsource.system.mapper.WxuserMapper;
import cn.itsource.system.service.ILogininfoService;
import cn.itsource.system.service.IMenuService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 业务实现类：
 */
@Service
public class LogininfoServiceImpl extends BaseServiceImpl<Logininfo> implements ILogininfoService {
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private LogininfoMapper logininfoMapper;
    @Autowired
    private RedisTemplate<String,Object> redisTemplate;
    @Autowired
    private WxuserMapper wxuserMapper;
    @Autowired
    private IMenuService iMenuService;
    @Override
    @Transactional
    public void register(PhoneUserFormRegisterDto registerDto, int i) {
        if(i==1){//1表示是普通用户
            Logininfo logininfo = new Logininfo();
            logininfo.setDisable(true);
            logininfo.setPhone(registerDto.getPhone());
            String salt = StrUtils.getComplexRandomString(32);
            logininfo.setSalt(salt);
            String md5password = SecureUtil.md5(salt + registerDto.getPassword());
            logininfo.setPassword(md5password);
            logininfo.setType(i);
            logininfo.setUsername(registerDto.getPhone());
            super.save(logininfo);
            //不仅要保存logininfo表还要保存 user
            User user = new User();
            BeanUtils.copyProperties(logininfo,user);
            user.setCreatetime(new Date());
            user.setLogininfoId(logininfo.getId());
            user.setState(1);
            userMapper.save(user);
        }else {
            //管理员的保存
        }
    }

    /**
     * 登录逻辑实现
     * @param loginDto
     * @param b true 开启密码校验   false 关闭密码校验
     * @return
     */
    @Override
    public AjaxResult login(LoginDto loginDto, Boolean b) {
        //根据用户名去查询数据库
        Logininfo logininfo = logininfoMapper.selectByUsernamePhoneEmail(loginDto.getUsername(),loginDto.getType());
        if(logininfo == null){
            // 没查到 抛异常
            throw new BusinessException(ErrorCode.BUSINESS_LOGIN_SYSTEM_ERROR.getCode());
        }
        if(b){//需不需要密码校验
            // 查到了
            String password = loginDto.getPassword();
            String salt = logininfo.getSalt();
            String saltPassword = SecureUtil.md5(salt + password);
            // 比较密码对不对
            if(!logininfo.getPassword().equals(saltPassword)){
                throw new BusinessException(ErrorCode.BUSINESS_LOGIN_SYSTEM_ERROR.getCode());
            }
        }
        // 生成token
//        String token = UUID.randomUUID().toString();
        // 保存redis  因为存放的是对象 所有要记住序列化   过期时间30分钟
//        redisTemplate.opsForValue().set(token,logininfo,30, TimeUnit.MINUTES);

        logininfo.setPassword("");
        logininfo.setSalt("");
        LoginData loginData = new LoginData();
        loginData.setLogininfo(logininfo);
        // 返回 token 和 用户信息
        Map<String,Object> map = new HashMap<>(4);
        String token = JwtUtils.getToken(loginData, 24 * 60 * 60 * 7);
        if(loginDto.getType() == 1){//判断是否是前台用户
            map.put("token",token);
            //特殊 清空密码返回  为了保证安全
            map.put("user",logininfo);
            return AjaxResult.me().setResultObj(map);
        }
        List<Menu> menuList = logininfoMapper.selectMenuByLoginInfoId(logininfo.getId());
        List<Long> pids = menuList.stream().map(Menu::getParentId).distinct().collect(Collectors.toList());
        List<Menu> top = iMenuService.selectMenu(pids);
        top.addAll(menuList);
        //menus 进行数据处理 处理成一棵树
        List<Menu> menus = iMenuService.getMenuTree1(top);
        loginData.setMenus(menus);
        List<String> permissions =  logininfoMapper.selectPermissionByLoginInfoId(logininfo.getId());
        loginData.setPermissions(permissions);
        token = JwtUtils.getToken(loginData, 24 * 60 * 60 * 7);

        map.put("token",token);
        //特殊 清空密码返回  为了保证安全
        map.put("user",logininfo);
        map.put("menus",menus);
        map.put("permission",permissions);
        return AjaxResult.me().setResultObj(map);
    }

    /**
     * 需求  必须绑定已有账号
     * @param bindDto
     * @return
     */
    @Override
    public AjaxResult bind(BindDto bindDto) {
        String username = bindDto.getUsername();
        Logininfo logininfo = logininfoMapper.selectByUsernamePhoneEmail(username,bindDto.getType());
        if(logininfo == null){
            throw new BusinessException(ErrorCode.BUSINESS_LOGIN_SYSTEM_ERROR.getCode());
        }
        //密码校验
        // 查到了
        String password = bindDto.getPassword();
        String salt = logininfo.getSalt();
        String saltPassword = SecureUtil.md5(salt + password);
        // 比较密码对不对
        if(!logininfo.getPassword().equals(saltPassword)){
            throw new BusinessException(ErrorCode.BUSINESS_LOGIN_SYSTEM_ERROR.getCode());
        }
        //进行绑定成功了
        String openId = bindDto.getOpenId();
        Wxuser wxuser = wxuserMapper.selectByOpenid(openId);
        User user =  userMapper.selectByLoginInfoId(logininfo.getId());
        if(wxuser != null){
            wxuser.setUserId(user.getId());
            wxuserMapper.update(wxuser);
        }
        //登录
        LoginDto loginDto = new LoginDto();
        loginDto.setType(1);
        loginDto.setUsername(username);
        AjaxResult login = login(loginDto, false);
        return login;
    }
}
